package com.xunk.system.service.impl;

import com.google.common.collect.Lists;
import com.xunk.common.core.constant.CacheConstants;
import com.xunk.common.core.constant.MessageNotifyConstants;
import com.xunk.common.core.constant.UserConstants;
import com.xunk.common.core.exception.CustomException;
import com.xunk.common.core.utils.DataUtils;
import com.xunk.common.core.utils.IdUtils;
import com.xunk.common.core.utils.XunkAssert;
import com.xunk.common.core.web.domain.AjaxResult;
import com.xunk.common.datascope.annotation.DataScope;
import com.xunk.common.redis.service.RedisService;
import com.xunk.common.security.utils.SecurityUtils;
import com.xunk.equipment.api.RemoteEquipmentService;
import com.xunk.equipment.api.domain.MessageNotificationDO;
import com.xunk.system.api.RemoteUserService;
import com.xunk.system.api.domain.SysDept;
import com.xunk.system.api.domain.SysHome;
import com.xunk.system.api.domain.SysUser;
import com.xunk.system.api.model.UserDeptInfo;
import com.xunk.system.domain.SysBimModel;
import com.xunk.system.domain.SysHomeResponse;
import com.xunk.system.domain.SysUserHome;
import com.xunk.system.entity.HomeDO;
import com.xunk.system.mapper.SysBimModelMapper;
import com.xunk.system.mapper.SysDeptMapper;
import com.xunk.system.mapper.SysHomeMapper;
import com.xunk.system.mapper.SysTenementMapper;
import com.xunk.system.service.ISysHomeService;
import com.xunk.system.service.ISysSceneService;
import com.xunk.system.vo.AllotMasterVO;
import com.xunk.system.vo.MasterBindHomeRequestVO;
import com.xunk.system.vo.SysUserRoughInfo;
import com.xunk.system.vo.UserHomeInfoResponseVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 家庭房屋信息Service业务层处理
 *
 * @author ruoyi
 * @date 2021-03-10
 */
@Service
@Slf4j
public class SysHomeServiceImpl implements ISysHomeService {

    @Autowired
    private SysHomeMapper sysHomeMapper;

    @Autowired
    private SysDeptMapper sysDeptMapper;

    @Autowired
    private RemoteEquipmentService remoteEquipmentService;

    @Autowired
    private SysBimModelMapper modelMapper;

    @Autowired
    private SysTenementMapper tenementMapper;

    @Autowired
    private ISysSceneService sceneService;

    @Autowired
    RemoteUserService remoteUserService;

    @Autowired
    RedisService service;

    @Autowired
    TokenStore tokenStore;

    /**
     * 查询家庭房屋信息
     *
     * @param homeId 家庭房屋信息ID
     * @return 家庭房屋信息
     */
    @Override
    public SysHome selectSysHomeById(Long homeId) {
        return sysHomeMapper.selectSysHomeById(homeId);
    }

    @Override
    public List<SysHome> selectSysHomeByCode(String inviteCode) {
        return sysHomeMapper.selectSysHomeByCode(inviteCode);
    }

    /**
     * 查询家庭房屋信息列表
     *
     * @param sysHome 家庭房屋信息
     * @return 家庭房屋信息
     */
    @Override
    @DataScope(deptAlias = "h")
    public List<SysHomeResponse> selectSysHomeList(SysHome sysHome) {
        return sysHomeMapper.selectSysHomeList(sysHome);
    }

    /**
     * 新增家庭房屋信息
     *
     * @param sysHome 家庭房屋信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public int insertSysHome(SysHome sysHome) {

        SysDept info = sysHomeMapper.selectDeptById(sysHome.getParentId());
        // 如果父节点不为正常状态,则不允许新增子节点
        if (!UserConstants.DEPT_NORMAL.equals(info.getStatus())) {
            throw new CustomException("部门停用，不允许新增");
        }
        SysDept dept = new SysDept();
        if (sysHome.getUserId() != null) {
            SysUser user = sysHomeMapper.selectUserByUserId(sysHome.getUserId());
            dept.setLeader(user.getUserName());
        } else {
            sysHome.setInviteCode(IdUtils.generateId());
        }
        dept.setCreateBy(SecurityUtils.getUsername());
        dept.setAncestors(info.getAncestors() + "," + sysHome.getParentId());
        String owerId = IdUtils.fastSimpleUUID();
        dept.setOwnerId(owerId);
        dept.setDeptName(sysHome.getAddress());
        dept.setParentId(sysHome.getParentId());
        dept.setRank(4);
        sysHomeMapper.insertDept(dept);
        StringBuilder address = new StringBuilder();
        for (String ancestor : info.getAncestors().split(",")) {
            if ("0".equals(ancestor)) {
                continue;
            }
            address.append(sysHomeMapper.selectDeptById(Long.parseLong(ancestor)).getDeptName());
        }
        address.append(sysHome.getAddress());
        //  校验是否存在相同的家庭信息
        Long count = sysHomeMapper.selectSysHomeByAddress(address.toString());
        XunkAssert.isTrue(count == 0, "存在重复的家庭信息，无需继续添加");
        //  填充字段
        sysHome.setCreateBy(dept.getCreateBy());
        sysHome.setDeptId(dept.getDeptId());
        sysHome.setAddress(address.toString());
        sysHome.setUpdateTime(new Date());
        resolveModelDesc(sysHome);
        sysHomeMapper.insertSysHome(sysHome);
        service.setCacheObject(CacheConstants.FIND_DEPTID_BY_OWNID + owerId, dept.getDeptId());
        service.setCacheObject(CacheConstants.FIND_OWNID_BY_DEPTID + dept.getDeptId(), owerId);
        if (sysHome.getUserId() != null) {
            sysHomeMapper.insertUserHomeRelation(sysHome.getUserId(), sysHome.getHomeId(), 1);
        }
        sceneService.insertSysSceneHome(sysHome.getHomeId());
        return 1;
    }

    private void resolveModelDesc(SysHome sysHome) {
        Long modelId = sysHome.getModelId();
        if (DataUtils.isNotEmpty(modelId)) {
            SysBimModel sysBimModel = modelMapper.selectSysBimModelById(modelId);
            sysHome.setDescription(sysBimModel.getDescription());
        }
    }

    /**
     * 修改家庭房屋信息
     *
     * @param sysHome 家庭房屋信息
     * @return 结果
     */
    @Override
    public int updateSysHome(SysHome sysHome) {
        resolveModelDesc(sysHome);
        return sysHomeMapper.updateSysHome(sysHome);
    }

    /**
     * 批量删除家庭房屋信息
     *
     * @param homeIds 需要删除的家庭房屋信息ID
     * @return 结果
     */
    @Override
    public int deleteSysHomeByIds(Long[] homeIds) {
        return sysHomeMapper.deleteSysHomeByIds(homeIds);
    }

    /**
     * 删除家庭房屋信息信息
     *
     * @param homeId 家庭房屋信息ID
     * @return 结果
     */
    @Override
    public int deleteSysHomeById(Long homeId) {
        return sysHomeMapper.deleteSysHomeById(homeId);
    }

    /**
     * 查询属于该房屋的家庭成员列表信息
     *
     * @param homeId 房屋id
     * @return 家庭成员列表
     */
    @Override
    public List<SysUser> selectHomeMemberByHomeId(Long homeId) {
        return sysHomeMapper.selectHomeMemberByHomeId(homeId);
    }

    /**
     * 移除家庭成员用户
     *
     * @param userId 用户id
     * @param homeId 家庭id
     */
    @Override
    public void removeUserFromHome(Long userId, Long homeId) {

        // TODO 将成员从家庭删除后，要考虑到被移除人员的app登录状态和信息，实时更新Token
        // 对操作人鉴权，不是房主不能操作删除功能
        int i = sysHomeMapper.selectIsHomeMaster(SecurityUtils.getUserId(), homeId);
        XunkAssert.isTrue(i != 0, "非当前家庭房主，不能移除该家庭成员");
        // 校验是否是房主，房主不能移除自己
        // 房主userId is_master 为1 且 homeId equals
        i = sysHomeMapper.selectIsHomeMaster(userId, homeId);
        XunkAssert.isTrue(i == 0, "房主不能移除");
        sysHomeMapper.removeUserFromHome(userId, homeId);

        // 清除当前家庭 SCENE:SCENE_HOME_ID_LIST 缓存
        service.deleteObject(USER_HOME_RELATION + userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void masterBindHome(MasterBindHomeRequestVO requestVO) {
        // 根据邀请码查询当前房子信息
        List<SysHome> sysHomeList = sysHomeMapper.selectSysHomeByCode(requestVO.getInviteCode());
        XunkAssert.notEmpty(sysHomeList, "该邀请码无效哦，请联系您的物业管理人员");
        XunkAssert.isTrue(sysHomeList.size() == 1, "邀请码重复，请联系管理员");
        SysHome sysHome = sysHomeList.get(0);
//        XunkAssert.isTrue(sysHome.getDeptId().equals(requestVO.getDeptId()), "绑定的房屋信息不正确，请重新选择房屋");

        // 为了防止重新生成邀请码导致再次绑定房主，需要校验一个家庭只能有一个房主
        Long homeId = sysHome.getHomeId();
        long countHomeMaster = sysHomeMapper.countHomeMaster(homeId);
        XunkAssert.isTrue(countHomeMaster < 1, "该家庭已存在房主，一个家庭只能存在一个房主角色");
        // 存入关系数据,更新当前用户角色为房主角色
        Long userId = SecurityUtils.getUserId();
        sysHomeMapper.insertUserHomeRelation(userId, homeId, UserConstants.HOME_MASTER);

        // 并且重置邀请码为空
        sysHomeMapper.invalidHomeInviteCodeByHomeId(homeId);

        // 发送系统消息
        try {
            MessageNotificationDO messageNotificationDO = new MessageNotificationDO();
            messageNotificationDO.setTitle("恭喜入住新家");
            SysDept sysDept = sysDeptMapper.findCommunityNameByHomeDeptId(sysHome.getDeptId());
            messageNotificationDO.setContent("尊敬的业主，恭喜您入住" + Optional.ofNullable(sysDept).map(SysDept::getDeptName).orElse("新家。"));
            messageNotificationDO.setDeptId(sysHome.getDeptId());
            messageNotificationDO.setUserId(userId);
            messageNotificationDO.setType(MessageNotifyConstants.SYSTEM_TYPE);
            messageNotificationDO.setCreateTime(new Date());
            remoteEquipmentService.insertMessageNotification(Lists.newArrayList(messageNotificationDO));
        } catch (Exception e) {
            log.error("保存通知异常", e);
        }

        // 绑定成功后，将房主信息回填到Dept表中
        String username = SecurityUtils.getUsername();
        UserDeptInfo info = new UserDeptInfo();
        info.setDeptId(sysHome.getDeptId());
        info.setUsername(username);
        remoteUserService.fillInUserInfoToDept(info);
//        service.deleteObject(CacheConstants.OAUTH_ACCESS + SecurityUtils.getAuthentication());
    }

    private static String USER_HOME_RELATION = "SCENE:SCENE_HOME_ID_LIST:";

    @Override
    public void userBindHome(String qrCode) {

//        SysHome sysHome = sysHomeMapper.selectSysHomeById(homeId);
        SysHome sysHome = sysHomeMapper.selectSysHomeByOwnerId(qrCode);
        XunkAssert.isTrue(sysHome != null, "二维码无效，无法加入该家庭");
        Long homeId = sysHome.getHomeId();
        Long userId = SecurityUtils.getUserId();
        Long count = sysHomeMapper.checkHomeMemeber(homeId, userId);
        XunkAssert.isTrue(count == 0, "该成员已经在该家庭下，无需重复加入");
        sysHomeMapper.insertUserHomeRelation(userId, homeId, UserConstants.HOME_NORMAL);
        try {
            // 查询当前家庭的人数
            List<SysUser> sysUsers = sysHomeMapper.selectHomeMemberByHomeId(homeId);
            SysUser masterUser = sysUsers.stream().filter(SysUser::getMaster).findFirst().orElseThrow(RuntimeException::new);
            // 发送成员变动系统消息 (业主和本人)
            String homeName = Optional.ofNullable(sysHome.getHomeName()).orElse("新家");
            int size = sysUsers.size();
            Date now = new Date();
            MessageNotificationDO self = new MessageNotificationDO();
            self.setTitle("成员变动通知");
            self.setContent("尊敬的用户，您好，您已成功加入\"" + homeName + "\"\n 当前家庭成员共" + size + "人");
            self.setDeptId(sysHome.getDeptId());
            self.setUserId(userId);
            self.setCreateTime(now);
            self.setType(MessageNotifyConstants.SYSTEM_TYPE);

            MessageNotificationDO owner = new MessageNotificationDO();
            owner.setTitle("成员变动通知");
            owner.setContent("尊敬的业主，您好，您的家庭\"" + homeName + "\"有新的成员加入啦~\n 当前家庭成员共" + size + "人");
            owner.setDeptId(sysHome.getDeptId());
            owner.setUserId(masterUser.getUserId());
            owner.setCreateTime(now);
            owner.setType(MessageNotifyConstants.SYSTEM_TYPE);

            remoteEquipmentService.insertMessageNotification(Lists.newArrayList(self, owner));

            // 清除当前家庭 SCENE:SCENE_HOME_ID_LIST 缓存
            sysUsers.forEach(user -> {
                service.deleteObject(USER_HOME_RELATION + user.getUserId());
            });

        } catch (Exception e) {
            log.error("保存通知异常", e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void allotMasterToUser(AllotMasterVO masterVO, String authHeader) {

        Long userId = SecurityUtils.getUserId();
        // 查询当前用户是否对应家庭的房主
        List<SysUserHome> sysUserHomes = sysHomeMapper.listUserHome(userId);
        Integer isMaster = sysUserHomes.stream().filter(item -> Objects.equals(item.getHomeId(), masterVO.getHomeId())).map(SysUserHome::getIsMaster).findFirst().orElse(null);
        XunkAssert.isTrue(Objects.equals(isMaster, 1), "您不是房主，不能操作更改房主");

        //  校验被指定的用户是否也是该家庭成员
        Long count = sysHomeMapper.checkHomeMemeber(masterVO.getHomeId(), masterVO.getAimUserId());
        XunkAssert.isTrue(count > 0, "目标成员不是属于该家庭成员，请先邀请加入家庭后再操作！");

        //  opUserId is_master 改为 0
        sysHomeMapper.updateHomeRole(userId, masterVO.getHomeId(), UserConstants.HOME_NORMAL);
        //  aimUserId is_master 改为 1
        sysHomeMapper.updateHomeRole(masterVO.getAimUserId(), masterVO.getHomeId(), UserConstants.HOME_MASTER);
        //  回填修改dept表
        UserDeptInfo info = new UserDeptInfo();
        Long deptId = this.selectSysHomeById(masterVO.getHomeId()).getDeptId();
        info.setDeptId(deptId);
        info.setUsername(masterVO.getUserName());
        remoteUserService.fillInUserInfoToDept(info);

        //String tokenValue = authHeader.replace(OAuth2AccessToken.BEARER_TYPE, StringUtils.EMPTY).trim();
        //OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);

        // 清空 access token
        //tokenStore.removeAccessToken(accessToken);

        // 清空 refresh token
        //OAuth2RefreshToken refreshToken = accessToken.getRefreshToken();
        //tokenStore.removeRefreshToken(refreshToken);
    }

    @Override
    public UserHomeInfoResponseVO findHomeByUserId(Long userId) {
        UserHomeInfoResponseVO responseVO = new UserHomeInfoResponseVO();
        List<SysUserHome> sysUserHomes = sysHomeMapper.listUserHome(userId);
        if (DataUtils.isEmpty(sysUserHomes)) {
            return responseVO;
        }
        List<HomeDO> homes = sysHomeMapper.listHome(sysUserHomes.stream().map(SysUserHome::getHomeId).collect(Collectors.toList()));
        Map<Long, Integer> homeMasterMap = sysUserHomes.stream().collect(Collectors.toMap(SysUserHome::getHomeId, SysUserHome::getIsMaster, (a, b) -> a));
        responseVO.setHomeList(homes.stream().map(home -> {
            UserHomeInfoResponseVO.UserHomeInfo userHomeInfo = new UserHomeInfoResponseVO.UserHomeInfo();
            userHomeInfo.setHomeId(home.getHomeId());
            userHomeInfo.setHomeName(home.getHomeName());
            userHomeInfo.setModelUrl(home.getUrl());
            userHomeInfo.setAddress(home.getAddress());
            userHomeInfo.setIsMaster(homeMasterMap.get(home.getHomeId()));
            userHomeInfo.setDescription(parseHomeDescription(home.getDescription()));

            // 解析房屋层次
            String ancestors = home.getAncestors();

            List<Long> ancestorsIds = Arrays.stream(ancestors.replaceFirst("0,", "").split(",")).map(Long::valueOf).collect(Collectors.toList());
            userHomeInfo.setProjectId(ancestorsIds.get(0));
            userHomeInfo.setAreaId(ancestorsIds.get(1));
            userHomeInfo.setCommunityId(ancestorsIds.get(2));
            userHomeInfo.setDistrictCode(tenementMapper.selectDistinctCodeById(ancestorsIds.get(2)));
            return userHomeInfo;
        }).collect(Collectors.toList()));
        return responseVO;
    }

    @Override
    public void quitHome(Long homeId) {

        // 先查询当前家庭的家庭所有成员
        List<SysUser> sysUsers = sysHomeMapper.selectHomeMemberByHomeId(homeId);
        Long userId = SecurityUtils.getUserId();
        int i = sysHomeMapper.selectIsHomeMaster(userId, homeId);
        log.info("QuitHome -> {},{},IsMaster:{}", userId, homeId, i);
        XunkAssert.isTrue(i == 0, "房主不能退出自己家庭");
        int res = sysHomeMapper.removeUserFromHome(userId, homeId);
        XunkAssert.isTrue(res != 0, "该用户不在所在家庭中");

        MessageNotificationDO message = new MessageNotificationDO();
        SysUser master = sysUsers.stream().filter(SysUser::getMaster).findFirst().orElseThrow(() -> new RuntimeException("该家庭竟然没有房主~~~"));
        SysUser member = sysUsers.stream().filter(s -> Objects.equals(userId, s.getUserId())).findFirst().get();
        SysHome sysHome = sysHomeMapper.selectSysHomeById(homeId);
        message.setTitle("成员变动通知");
        message.setContent("尊敬的业主，您好，您的家庭成员\"" + member.getNickName() + "\"退出了您的家庭~\n当前家庭成员共" + (sysUsers.size() - 1) + "人");
        message.setType(MessageNotifyConstants.SYSTEM_TYPE);
        message.setUserId(master.getUserId());
        message.setDeptId(sysHome.getDeptId());
        message.setCreateTime(new Date());
        remoteEquipmentService.insertMessageNotification(Lists.newArrayList(message));
    }

    @Override
    public AjaxResult selectMasterAndHomeInfo(String qrCode) {

        try {
            SysHome sysHome = sysHomeMapper.selectSysHomeByOwnerId(qrCode);
            Map<String, Object> map = new HashMap<>();
            XunkAssert.notEmpty(sysHome, "不存在的家庭信息,无效二维码");
            map.put("address", sysHome.getAddress());
            map.put("homeName", sysHome.getHomeName());
            SysUserRoughInfo users = sysHomeMapper.selectMasterByHomeId(sysHome.getHomeId());
            XunkAssert.notEmpty(users, "系统错误，该家庭中无房主信息");
            map.put("avatar", users.getAvatar());
            map.put("rooms", parseHomeDescription(sysHome.getDescription()).values());
            return AjaxResult.success(map);
        } catch (Exception e) {
            throw new CustomException("无效的二维码");
        }
    }


    private Map<String, String> parseHomeDescription(String description) {

        try {
            Map<String, String> map = new HashMap<>();
            String[] split = description.substring(1, description.length() - 2).split(",");
            for (String s : split) {
                map.put(s.split(":")[0].replace("\"", ""), s.split(":")[1].replace("\"", ""));
            }
            return map;
        } catch (Exception e) {
            return new HashMap<>();
        }
    }
}
